﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Maticsoft.DBUtility;
using Nest;
using WinFormElasticSearch.EsHelper;

namespace WinFormElasticSearch
{
    public partial class Form1 : Form
    {
        public Lazy<string> lazyTest = new Lazy<string>(() =>
        {
            return "1";
        });

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string str = "liwei";
            MessageBox.Show(str.TestExd());

            //MessageBox.Show(lazyTest.IsValueCreated.ToString());
            //MessageBox.Show(lazyTest.Value);
            //MessageBox.Show(lazyTest.IsValueCreated.ToString());
            return;

            //var p = new ElasticsearchProvider();
            var t = ElasticsearchProvider.IndexExists("employee_test");
            MessageBox.Show(t.ToString());

            var emp = new Employee
            {
                FirstName = "Li",
                LastName = "Wei",
                Salary = 50000,
                Birthday = DateTime.Parse("1983-08-13"),
                IsManager = true,
                Hours = new TimeSpan(0,5,0)
            };

            try
            {
                ElasticsearchProvider.Index<Employee>(emp, "employee_test");
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //return;

            //var node = new Uri("http://localhost:9200");

            Stopwatch sw = new Stopwatch();
            sw.Start();

            var node = new Uri("http://101.132.67.99:9210");
            var settings = new ConnectionSettings(node);
            var client = new ElasticClient(settings);

            var descriptor = new CreateIndexDescriptor("hotel_top_search_tip_hotel")
                .Mappings(ms => ms
                    .Map<HotelPosSearchTip>(m => m.AutoMap())
                )
                .Settings(s => s.NumberOfShards(1)
                    .NumberOfReplicas(0));
            var response = client.CreateIndex(descriptor);

            sw.Stop();

            var rst = sw.ElapsedMilliseconds;

            MessageBox.Show(rst.ToString());

            ////基本配置
            //IIndexState indexState = new IndexState()
            //{
            //    Settings = new IndexSettings()
            //    {
            //        NumberOfReplicas = 1,//副本数
            //        NumberOfShards = 5//分片数
            //    }
            //};
            //////创建并Mapping
            //var rst = client.CreateIndex("hotel_pos_search_tip", p => p.InitializeUsing(indexState).Mappings(m => m.Map<HotelPosSearchTip>(mp => mp.AutoMap())));

            //var descriptor = new CreateIndexDescriptor("hotel_pos_search_tip")
            //    .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1))
            //    .Mappings(ms => ms
            //        .Map<HotelPosSearchTip>(m => m.AutoMap())
            //    );

            //client.CreateIndex(descriptor);

            MessageBox.Show("OK");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //return;

            var dt = DbHelperSQL.Query("SELECT * FROM HotelPosSearchTip WHERE CategOrder<7").Tables[0];

            if (dt != null && dt.Rows.Count > 0)
            {
                var list = new List<HotelPosSearchTip>();

                foreach (DataRow dr in dt.Rows)
                {
                    list.Add(new HotelPosSearchTip
                    {
                        PosKey = dr["PosKey"].ToString(),
                        PosDisText = dr["PosDisText"].ToString(),
                        CategCode = dr["CategCode"].ToString(),
                        CategName = dr["CategName"].ToString(),
                        CityCode = dr["CityCode"].ToString(),
                        CityName = dr["CityName"].ToString(),
                        Lat = dr["Lat"].ToString(),
                        Lng = dr["Lng"].ToString(),
                        OrderNum = Convert.ToInt32(dr["OrderNum"].ToString()),
                        CategOrder = Convert.ToInt32(dr["CategOrder"].ToString())
                    });
                }

                //var p = new ElasticsearchProvider();
                //ElasticsearchProvider.BulkIndex<HotelPosSearchTip>(list, "hotel_pos_search_tip");

                var node = new Uri("http://101.132.67.99:9210");
                var settings = new ConnectionSettings(node);
                var client = new ElasticClient(settings);

                var index = "hotel_pos_search_tip";
                if (!client.IndexExists(index).Exists)
                {
                    client.InitializeIndexMap<HotelPosSearchTip>(index);
                }

                var bulkRequest = new BulkRequest(index)
                {
                    Operations = new List<IBulkOperation>()
                };
                var idxops = list.Select(o => new BulkIndexOperation<HotelPosSearchTip>(o)).Cast<IBulkOperation>().ToList();
                bulkRequest.Operations = idxops;
                var response = client.Bulk(bulkRequest);

                if (!response.IsValid)
                    MessageBox.Show("新增数据失败:" + response.OriginalException.Message);

                Console.WriteLine("====CategOrder<7===OK!");
            }

            MessageBox.Show("OK");
        }

        private void button6_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            

            var dt = DbHelperSQL.Query("SELECT * FROM HotelPosSearchTip WHERE CategOrder>=7").Tables[0];

            if (dt != null && dt.Rows.Count > 0)
            {
                var list = new List<HotelNameSearchTip>();

                foreach (DataRow dr in dt.Rows)
                {
                    list.Add(new HotelNameSearchTip
                    {
                        PosKey = dr["PosKey"].ToString(),
                        PosDisText = dr["PosDisText"].ToString(),
                        CategCode = dr["CategCode"].ToString(),
                        CategName = dr["CategName"].ToString(),
                        CityCode = dr["CityCode"].ToString(),
                        CityName = dr["CityName"].ToString(),
                        Lat = dr["Lat"].ToString(),
                        Lng = dr["Lng"].ToString(),
                        OrderNum = Convert.ToInt32(dr["OrderNum"].ToString()),
                        CategOrder = Convert.ToInt32(dr["CategOrder"].ToString()),
                        HotelId = dr["HotelId"].ToString()
                    });
                }

                //var p = new ElasticsearchProvider();
                //p.BulkIndex<HotelPosSearchTip>(list, "hotel_top_search_tip_hotel");

                
                var node = new Uri("http://101.132.67.99:9210");
                var settings = new ConnectionSettings(node);
                var client = new ElasticClient(settings);

                var index = "hotel_name_search_tip";
                if (!client.IndexExists(index).Exists)
                {
                    client.InitializeIndexMap<HotelNameSearchTip>(index);
                }

                var bulkRequest = new BulkRequest(index)
                {
                    Operations = new List<IBulkOperation>()
                };
                var idxops = list.Select(o => new BulkIndexOperation<HotelNameSearchTip>(o)).Cast<IBulkOperation>().ToList();
                bulkRequest.Operations = idxops;

                sw.Start();
                var response = client.Bulk(bulkRequest);

                if (!response.IsValid)
                    MessageBox.Show("新增数据失败:" + response.OriginalException.Message);

                Console.WriteLine("====CategOrder>=7===OK!");
            }

            sw.Stop();

            MessageBox.Show("OK!" + sw.ElapsedMilliseconds.ToString());
        }

        private void button4_Click(object sender, EventArgs e)
        {
            var queryStr = textBox1.Text.Trim();

            var node = new Uri("http://101.132.67.99:9210");
            var settings = new ConnectionSettings(node).DefaultIndex("hotel_pos_search_tip");//.DefaultFieldNameInferrer((name) => name);
            settings.EnableTcpKeepAlive(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(2)).DisableDirectStreaming().PrettyJson();
            var client = new ElasticClient(settings);

            //var p = new ElasticsearchProvider();
            //var client = ElasticsearchProvider.ElasticClient;

            //var ids = new List<string> { "1", "2", "3" };
            //var bulkResponse = client.DeleteMany<HotelPosSearchTip>(ids.Select(x => new HotelPosSearchTip { PosKey = x }));

            //var searchResponse = client.Search<HotelPosSearchTip>(s => s
            //    .Index("hotel_pos_search_tip")
            //    .From(0)
            //    .Size(100)
            //    .Query(q => q
            //        .Match(m => m
            //            .Field(f => f.PosKey)
            //            .Query("火*")
            //            .Analyzer("ik_max_word")
            //            .Operator(Operator.Or)
            //        )
            //    )
            //);

            //var searchResponse = client.Search<HotelPosSearchTip>(s => s
            //    .Index("hotel_pos_search_tip")
            //    .From(0)
            //    .Size(100)
            //    .Query(q => q.Bool(b =>
            //        b.Should(m => m.QueryString(qs => qs.Fields(f => f.Fields(fs => fs.PosKey)).Query(queryStr)))
            //        .Must(m=>m.QueryString(qs=>qs.Fields(f=>f.Fields(fs => fs.CityCode)).Query("hangzhou"))))));

            //var searchRequest = new SearchRequest<HotelPosSearchTip>
            //{
            //    From = 0,
            //    Size = 10,
            //    MinScore = 0.5,
            //    Query = new MatchQuery
            //    {
            //        Field = Infer.Field<HotelPosSearchTip>(f => f.PosKey),
            //        Query = "Martijn"
            //    }
            //};
            //var sR = client.Search<HotelPosSearchTip>(searchRequest);

            #region 多推荐 排序 查询

            //must 条件
            var mustQuerys = new List<Func<QueryContainerDescriptor<HotelPosSearchTip>, QueryContainer>>();
            //CityCode
            mustQuerys.Add(mt => mt.Term(tm => tm.Field(fd => fd.CityCode).Value("hangzhou")));
            //mustQuerys.Add(mt => mt.QueryString(tm => tm.Fields(fd => fd.Fields(fs => fs.PosKey)).Query(queryStr)));
            ////CreateTime
            //mustQuerys.Add(mt => mt.DateRange(tm => tm.Field(fd => fd.CreateTime).GreaterThanOrEquals(DateTime.Now.AddDays(-1)).LessThanOrEquals(DateTime.Now)));
            //should 条件
            var shouldQuerys = new List<Func<QueryContainerDescriptor<HotelPosSearchTip>, QueryContainer>>();
            //PosKey
            shouldQuerys.Add(mt => mt.QueryString(tm => tm.Fields(fd => fd.Fields(fs=>fs.PosKey)).Query(queryStr)));
            //shouldQuerys.Add(mt => mt.Term(tm => tm.Field(fd => fd.PosKey).Value(2)));
            //排序
            Func<SortDescriptor<HotelPosSearchTip>, IPromise<IList<ISort>>> sortDesc = sd =>
            {
                //根据分值排序
                sd.Ascending(SortSpecialField.Score);

                //sd.Ascending(d => d.CategOrder);
                //sd.Ascending(d => d.OrderNum);


                //排序
                //if (useStateDesc)
                //    sd.Descending(d => d.State);
                //else
                //    sd.Descending(d => d.Id);
                return sd;
            };
            var searchResponse = client.Search<HotelPosSearchTip>(s => s
                .Index("hotel_top_search_tip_hotel")
                .MinScore(8)
                .Query(q => q.Bool(b => b.Should(shouldQuerys).Must(mustQuerys)))
                .Highlight(h => h
                        .PreTags("<tag1>")
                        .PostTags("</tag1>")
                        .Encoder(HighlighterEncoder.Html)
                        .Fields(fs => fs
                                .Field(p => p.PosKey))
                                    
                 )
                .Size(100)
                .From(0)
                //.Sort(sortDesc)
            );

            #endregion

            this.listBox1.Items.Clear();

            var r = searchResponse?.Documents;

            foreach (var highlightsInEachHit in searchResponse?.Hits.Select(d => d.Highlights))
            {

            }

            if (r != null)
            {
                r.ToList().ForEach(m =>
                {
                    this.listBox1.Items.Add(m.PosKey + "|" + m.PosDisText);
                    
                });
            }
        }

        private List<string> MultiQuery()
        {
            var returnList = new List<string>();
            var queryStr = textBox1.Text.Trim();
            var t = 0;

            Task<List<string>>[] tasks = new Task<List<string>>[2];
            for (int i = 0; i < tasks.Length; i++)
            {
                var indexName = "hotel_pos_search_tip";
                if (i == 1)
                    indexName = "hotel_top_search_tip_hotel";

                tasks[i] = Task.Factory.StartNew(() => QueryInfo(queryStr, indexName));
            }

            Task.WaitAny(tasks);

            for (int i = 0; i < tasks.Length; i++)
            {
                returnList.AddRange(tasks[i].Result);
            }

            return returnList;
        }

        private List<string> QueryInfo(string queryStr, string indexName)
        {
            var p = new ElasticsearchProvider();
            var client = ElasticsearchProvider.ElasticClient;

            var returnList = new List<string>();

            //var indexName = "hotel_pos_search_tip";
            //if (type == 2)
            //    indexName = "hotel_top_search_tip_hotel";

            #region 多推荐 排序 查询

            //must 条件
            var mustQuerys = new List<Func<QueryContainerDescriptor<HotelPosSearchTip>, QueryContainer>>();
            //CityCode
            mustQuerys.Add(mt => mt.Term(tm => tm.Field(fd => fd.CityCode).Value("hangzhou")));
            mustQuerys.Add(mt => mt.QueryString(tm => tm.Fields(fd => fd.Fields(fs => fs.PosKey)).Query(queryStr)));

            var searchResponse = client.Search<HotelPosSearchTip>(s => s
                    .Index(indexName)
                    //.MinScore(8)
                    .Query(q => q.Bool(b => b.Must(mustQuerys)))
                    .Size(5)
                    .From(0)
                //.Sort(sortDesc)
            );

            #endregion

            var r = searchResponse?.Documents;

            if (r != null)
            {
                r.ToList().ForEach(m =>
                {
                    returnList.Add(m.PosKey + "|" + m.PosDisText);
                });
            }

            return returnList;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            var r = MultiQuery();

            this.listBox1.Items.Clear();

            if (r != null)
            {
                r.ForEach(m =>
                {
                    this.listBox1.Items.Add(m);
                });
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.textBox1.Text))
            {
                MessageBox.Show("输入index");
                return;
            }

            var node = new Uri("http://101.132.67.99:9210");
            var settings = new ConnectionSettings(node);
            var client = new ElasticClient(settings);

            var index = this.textBox1.Text.Trim();
            if (!client.IndexExists(index).Exists)
            {
                MessageBox.Show("index不存在");
                return;
            }

            client.DeleteIndex(index);

            MessageBox.Show("OK");
        }

        private void button8_Click(object sender, EventArgs e)
        {
            var node = new Uri("http://101.132.67.99:9210");
            var settings = new ConnectionSettings(node).DefaultIndex("hotel_name_search_tip");
            var client = new ElasticClient(settings);

            //797a967a-23c9-4a32-8847-2752e8cf3202
            DocumentPath<HotelNameSearchTip> deletePath = new DocumentPath<HotelNameSearchTip>("797a967a-23c9-4a32-8847-2752e8cf3202");
            var rst = client.Delete(deletePath);
            

            //IDeleteRequest request = new DeleteRequest("hotel_name_search_tip", "hotel_name_search_tip", "797a967a-23c9-4a32-8847-2752e8cf3202");
            //var rst = client.Delete(request);

            MessageBox.Show("ok!");
        }

        private void button9_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            
            var dt = DbHelperSQL.Query("SELECT Id,[Name],[Address],[Phone],[Longitude],[Latitude],(SELECT Code FROM Cities WHERE HotelBasicInfoes.[CityId]=Cities.Id) CityCode FROM HotelBasicInfoes WHERE CityId='F9D2DD88-B2E6-478D-9DD8-907E0B85AA1A' and [Longitude]>0 and [Latitude]>0").Tables[0];

            if (dt != null && dt.Rows.Count > 0)
            {
                var node = new Uri("http://127.0.0.1:9200");
                var settings = new ConnectionSettings(node);
                var client = new ElasticClient(settings);

                var index = "hotel_info";
                if (!client.IndexExists(index).Exists)
                {
                    client.InitializeIndexMap<HotelInfo>(index);
                }

                var list = new List<HotelInfo>();

                foreach (DataRow dr in dt.Rows)
                {
                    try
                    {
                        var lont = Convert.ToDouble(dr["Longitude"]);
                        var lat = Convert.ToDouble(dr["Latitude"]);

                        var location = new GeoLocation(lat, lont);

                        list.Add(new HotelInfo
                        {
                            Name = dr["Name"].ToString(),
                            Address = dr["Address"].ToString(),
                            Location = location,
                            CityCode = dr["CityCode"].ToString(),
                            HotelId = dr["Id"].ToString()
                        });
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                    }                    
                }

                //var p = new ElasticsearchProvider();
                //p.BulkIndex<HotelPosSearchTip>(list, "hotel_top_search_tip_hotel");
                
                var bulkRequest = new BulkRequest(index)
                {
                    Operations = new List<IBulkOperation>()
                };
                var idxops = list.Select(o => new BulkIndexOperation<HotelInfo>(o)).Cast<IBulkOperation>().ToList();
                bulkRequest.Operations = idxops;

                sw.Start();
                var response = client.Bulk(bulkRequest);

                if (!response.IsValid)
                    MessageBox.Show("新增数据失败:" + response.OriginalException.Message);

                Console.WriteLine("====HotelInfo===OK!");
            }

            sw.Stop();
            
            MessageBox.Show("OK!" + sw.ElapsedMilliseconds.ToString());
        }

        private void button10_Click(object sender, EventArgs e)
        {
            var p = new ElasticsearchProvider();
            var client = ElasticsearchProvider.ElasticClient;

            var returnList = new List<string>();

            var indexName = "hotel_info";
            //if (type == 2)
            //    indexName = "hotel_top_search_tip_hotel";

            var query = new GeoDistanceQuery
            {
                Boost = 1.1,
                Name = "location",
                Field = Infer.Field<HotelInfo>(m => m.Location),
                DistanceType = GeoDistanceType.Arc,
                Location = new GeoLocation(30.2159409, 120.1358210),
                Distance = "2000.0m",
                ValidationMethod = GeoValidationMethod.IgnoreMalformed
            };

            #region 多推荐 排序 查询

            ////must 条件
            //var mustQuerys = new List<Func<QueryContainerDescriptor<HotelPosSearchTip>, QueryContainer>>();
            ////CityCode
            //mustQuerys.Add(mt => mt.Term(tm => tm.Field(fd => fd.CityCode).Value("hangzhou")));
            //mustQuerys.Add(mt => mt.QueryString(tm => tm.Fields(fd => fd.Fields(fs => fs.PosKey)).Query(queryStr)));

            var searchResponse = client.Search<HotelInfo>(s => s
                    .Index(indexName)
                    //.MinScore(8)
                    //.Query(q => q.Bool(b => b.Must(query)))
                    .Size(5)
                    .From(0)
                //.Sort(sortDesc)
            );


            #endregion

            var r = searchResponse?.Documents;

            if (r != null)
            {
                r.ToList().ForEach(m =>
                {
                    returnList.Add(m.Name + "|" + m.Address);
                });
            }

            //return returnList;
        }
    }

    public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Salary { get; set; }
        public DateTime Birthday { get; set; }
        public bool IsManager { get; set; }
        public TimeSpan Hours { get; set; }
    }

    /// <summary>
    /// 酒店提示关键词搜索
    /// </summary>
    //[ElasticsearchType(Name = "hotel_pos_search_tip")]
    public class HotelPosSearchTip
    {
        [Text(Name= "PosKey", Index = true, Analyzer="ik_max_word")]
        public string PosKey { get; set; }

        [Keyword(Name = "PosDisText", Index = false)]
        public string PosDisText { get; set; }

        [Keyword(Name = "CategCode", Index = true)]
        public string CategCode { get; set; }

        [Keyword(Name = "CategName", Index = true)]
        public string CategName { get; set; }

        [Keyword(Name = "CityCode", Index = true)]
        public string CityCode { get; set; }

        [Keyword(Name = "CityName", Index = true)]
        public string CityName { get; set; }

        [Keyword(Name = "Lat", Index = false)]
        public string Lat { get; set; }

        [Keyword(Name = "Lng", Index = false)]
        public string Lng { get; set; }

        [Number(NumberType.Integer, Name = "OrderNum")]
        public int OrderNum { get; set; }

        [Number(NumberType.Integer, Name = "CategOrder")]
        public int CategOrder { get; set; }

        [Keyword(Name = "HotelId", Index = false)]
        public string HotelId { get; set; }
    }

    /// <summary>
    /// 酒店提示关键词搜索
    /// </summary>
    [ElasticsearchType(IdProperty = "HotelId", Name = "hotel_name_search_tip")]
    public class HotelNameSearchTip
    {
        [Text(Name = "PosKey", Index = true, Analyzer = "ik_max_word")]
        public string PosKey { get; set; }

        [Keyword(Name = "PosDisText", Index = false)]
        public string PosDisText { get; set; }

        [Keyword(Name = "CategCode", Index = true)]
        public string CategCode { get; set; }

        [Keyword(Name = "CategName", Index = true)]
        public string CategName { get; set; }

        [Keyword(Name = "CityCode", Index = true)]
        public string CityCode { get; set; }

        [Keyword(Name = "CityName", Index = true)]
        public string CityName { get; set; }

        [Keyword(Name = "Lat", Index = false)]
        public string Lat { get; set; }

        [Keyword(Name = "Lng", Index = false)]
        public string Lng { get; set; }

        [Number(NumberType.Integer, Name = "OrderNum")]
        public int OrderNum { get; set; }

        [Number(NumberType.Integer, Name = "CategOrder")]
        public int CategOrder { get; set; }

        [Keyword(Name = "HotelId", Index = true)]
        public string HotelId { get; set; }
    }

    /// <summary>
    /// 酒店基础信息
    /// </summary>
    [ElasticsearchType(IdProperty = "HotelId", Name = "hotel_info")]
    public class HotelInfo
    {
        [Text(Name = "Name", Index = true, Analyzer = "ik_max_word")]
        public string Name { get; set; }

        [Keyword(Name = "HotelId", Index = true)]
        public string HotelId { get; set; }

        [Keyword(Name = "Address", Index = false)]
        public string Address { get; set; }

        [Keyword(Name = "Phone", Index = true)]
        public string Phone { get; set; }

        [Keyword(Name = "CityCode", Index = true)]
        public string CityCode { get; set; }

        public GeoLocation Location { get; set; }
    }
}
